#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <windows.h>

#define TOOL_PATH_LEN 1024
#define FULL_PATH_LEN 16384
#define LOG_INFO(...) printf(__VA_ARGS__)

char tool_path[FULL_PATH_LEN] = "C:\\Users\\28328\\.vscode\\extensions\\ms-vscode.cpptools-1.3.1\\LLVM\\bin\\";
char tool_name[128]           = "clang-format.exe";
char format_file_name[]       = ".clang-format";

static int path_index = 0;

static int   get_format_file(char *file_path);
static int   rm_format_file(void);
static int   hj_copy_file(char *old_file, char *new_file);
static _Bool is_dir(char *name);
static void  hide_windows_console(void);

int main(int argv, char *argc[])
{
    // 关闭console窗口，静默执行
    hide_windows_console();

    char full_path[FULL_PATH_LEN]   = {0};
    char format_file[TOOL_PATH_LEN] = {0};

    memcpy(full_path, tool_path, TOOL_PATH_LEN);
    memcpy(format_file, tool_path, TOOL_PATH_LEN);

    strncat(full_path, tool_name, FULL_PATH_LEN - strlen(tool_path));

    strncat(format_file, format_file_name, TOOL_PATH_LEN - strlen(tool_path));

    if (argv == 1)
    {
        LOG_INFO("Please enter parameter.\n");
        return 0;
    }

    for (int i = 1; i < argv; i++)
    {
        LOG_INFO("%s\n", argc[i]);
        strncat(full_path, " ", FULL_PATH_LEN - strlen(tool_path));
        strncat(full_path, argc[i], FULL_PATH_LEN - strlen(tool_path));

        if (0 == strncmp(argc[i], "-i", 2))
        {
            path_index = i + 1;
        }
    }

    LOG_INFO("full_path: %s\n", full_path);
    LOG_INFO("format_file: %s\n", format_file);

    /* 格式化目录下的所有.c .h 文件 */
    if (is_dir(argc[path_index]))
    {
        char work_path[256] = {0};
        strcat(work_path, argc[path_index]);

        if (work_path[strlen(work_path) - 1] != '\\')
        {
            strcat(work_path, "\\");
        }

        LOG_INFO("work path: %s\n", work_path);
        int ret = chdir(work_path);
        if (ret)
        {
            LOG_INFO("%s:%d: chdir error: %d\n", __func__, __LINE__, ret);
            return 0;
        }

        char temp[FULL_PATH_LEN] = {0};
        memcpy(temp, full_path, FULL_PATH_LEN);
        strcat(temp, "*.c");

        get_format_file(format_file);
        system(temp);
        rm_format_file();

        memcpy(temp, full_path, FULL_PATH_LEN);
        strcat(temp, "*.h");

        get_format_file(format_file);
        system(temp);
        rm_format_file();
    }
    else
    { /* 格式化单个文件 */
        get_format_file(format_file);
        system(full_path);
        rm_format_file();
    }

    return 0;
}

static int get_format_file(char *file_path)
{
    int ret = hj_copy_file(file_path, format_file_name);
    if (ret)
    {
        LOG_INFO("%s:%d: copy file error: %d\n", __func__, __LINE__, ret);
        return ret;
    }

    return ret;
}

static int rm_format_file(void)
{
    uint32_t ret = remove(format_file_name);
    if (ret)
    {
        LOG_INFO("%s:%d: remove format file error: %d\n", __func__, __LINE__, ret);
    }

    return ret;
}

static int hj_copy_file(char *old_file, char *new_file)
{
    if (!old_file || !new_file)
    {
        return 1;
    }
#define BUFFER_LEN 16384

    FILE *fp                 = NULL;
    FILE *fp_out             = NULL;
    char  buffer[BUFFER_LEN] = {0};
    int   ret                = 0;

    fp = fopen(old_file, "rb");
    if (!fp)
    {
        LOG_INFO("%s:%d: open file error.\n", __func__, __LINE__);
        return 2;
    }

    ret = fread(buffer, sizeof(char), BUFFER_LEN, fp);
    if (ret <= 0)
    {
        LOG_INFO("%s:%d: read file error.\n", __func__, __LINE__);
        return 3;
    }

    fclose(fp);

    fp_out = fopen(new_file, "wb");
    if (!fp_out)
    {
        LOG_INFO("%s:%d: open file error.\n", __func__, __LINE__);
        return 4;
    }

    ret = fwrite(buffer, sizeof(char), ret, fp_out);
    if (ret <= 0)
    {
        LOG_INFO("%s:%d: write file error.\n", __func__, __LINE__);
        return 5;
    }

    fclose(fp_out);

    return 0;
}

static _Bool is_dir(char *name)
{
    struct _stat buf;
    int          result = 0;
    result              = _stat(name, &buf);
    if (_S_IFDIR & buf.st_mode)
    {
        return TRUE;
    }
    else if (_S_IFREG & buf.st_mode)
    {
        return FALSE;
    }
}

static void hide_windows_console()
{
    HWND hwnd = GetForegroundWindow(); //获取程序启动时的窗口
    if (hwnd)
    {
        ShowWindow(hwnd, SW_HIDE); //设置指定窗口的显示状态
    }
}